﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using HtmlAgilityPack;
using System.Net;

namespace ArchiveSearch
{
    class Archive
    {
        DebugConsole debug;
        WebClient wc;
        const string MLPGArchiveURL =
            //"file:///F:/Users/Owner/Desktop/mlpg.htm";
            "http://arch.413chan.net/mlpgeneral/";
        public List<ArchivedThread> Threads { get; set; }
        private string downloaded = null;

        public Archive(DebugConsole debug)
        {
            this.debug = debug;
            wc = new WebClient();
            wc.Headers.Add("user-agent", "ChanSharp Library (contact cosinemlpg@gmail.com)");
            Threads = new List<ArchivedThread>();
        }

        public void Start()
        {
            WriteLine("Starting!");

            wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(wc_DownloadProgressChanged);
            wc.DownloadStringCompleted += new DownloadStringCompletedEventHandler(wc_DownloadStringCompleted);

            HtmlDocument archfrontpage = new HtmlDocument();
            archfrontpage.LoadHtml(DownloadPage(MLPGArchiveURL));

            HtmlNode nodeTop = archfrontpage.DocumentNode;

            if (nodeTop.InnerText.Contains("mysql_connect()"))
            {
                System.Windows.Forms.MessageBox.Show("MLPG Archive is down. Try later.");
                Environment.Exit(1);
            }

            HtmlNodeCollection tables = nodeTop.SelectNodes("html/body/center/div/table[@align='center']");

            WriteLine("There are " + tables.Count + " month-tables.");

            List<HtmlNode> allRows = new List<HtmlNode>();

            //for every table
            for (int t = 0; t < tables.Count; t++)
            {
                //get the rows
                HtmlNodeCollection tableRows = tables[t].SelectNodes("tr");
                WriteLine(tableRows.Count + " threads in table " + t + ".");

                //and add them to the list of rows
                for (int r = 0; r < tableRows.Count; r++)
                {
                    allRows.Add(tableRows[r]);
                }
            }

            WriteLine("That's " + allRows.Count + " rows total. Take out the month headers and...");

            //deselect the table header rows (e.g. "<tr> ... August 2012 ... </tr>")
            List<HtmlNode> goodRows = (from n in allRows
                                       where n.SelectSingleNode("th") == null
                                       select n).ToList<HtmlNode>();

            WriteLine("We get " + goodRows.Count + " threads.");

            for (int th = 0; th < goodRows.Count; th++)
            {
                ArchivedThread thisThread = Parse(goodRows[th]);
                Threads.Add(thisThread);
            }
            WriteLine("Reversing.");
            Threads.Reverse();
            WriteLine("That's all.");
        }

        public ArchivedThread Parse(HtmlNode row)
        {
            DateTime Date;
            string URL;
            int OPID;
            int Replies;
            int Images;
            int Sages;

            HtmlNode[] td = row.SelectNodes("td").ToArray();

            Date = DateTime.Parse(td[0].InnerText);
            URL = td[1].SelectSingleNode("a").GetAttributeValue("href", "!");
            OPID = int.Parse(td[1].SelectSingleNode("a").InnerText.Trim());
            Replies = int.Parse(td[2].InnerText.Substring(0, td[2].InnerText.IndexOf(' ')));
            Images = int.Parse(td[3].InnerText.Substring(0, td[3].InnerText.IndexOf(' ')));
            Sages = int.Parse(td[4].InnerText.Substring(0, td[4].InnerText.IndexOf(' ')));

            ArchivedThread archivedThread = new ArchivedThread(Date, URL, OPID, Replies, Images, Sages);

            return archivedThread;

            throw new NotImplementedException();
        }


        #region helper
        public void Abort()
        {
            wc.CancelAsync();
        }

        private void Write(string msg)
        {
            debug(msg);
        }

        private void WriteLine(string msg)
        {
            Write(msg + "\r\n");
        }

        private void WriteLine()
        {
            Write("\r\n");
        }

        private string DownloadPage(string page)
        {
            WriteLine("Downloading page " + page);
            wc.DownloadStringAsync(new Uri(page));
            WaitForComplete();
            string fin = downloaded + "";
            downloaded = null;
            WriteLine("Done!");
            return fin;
        }

        private void WaitForComplete()
        {
            while (downloaded == null) Thread.Sleep(5);
        }

        void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            downloaded = e.Result;
        }

        private void wc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            Write(e.TotalBytesToReceive - e.BytesReceived + "...");
        }
        #endregion
    }

    struct ArchivedThread
    {
        public DateTime Date;
        public string URL;
        public int OPID;
        public int Replies;
        public int Images;
        public int Sages;

        public ArchivedThread(DateTime Date, string URL, int OPID, int Replies, int Images, int Sages)
        {
            this.Date = Date;
            this.URL = URL;
            this.OPID = OPID;
            this.Replies = Replies;
            this.Images = Images;
            this.Sages = Sages;
        }

        public override string ToString()
        {
            return URL + " " + OPID + " on " + Date.ToString("MM/dd/yy") + " with " + Replies + " reps, " + Images + " imgs, " + Sages + " sages";
        }
    }
}
